/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.edit.handlers;

import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.uml2.uml.CombinedFragment;
import org.eclipse.uml2.uml.InteractionConstraint;
import org.eclipse.uml2.uml.InteractionOperand;

import com.cea.papyrus.core.utils.LookForElement;
import com.cea.papyrus.diagram.sequence.sedi.edit.command.AnalyseOwnerCommand;
import com.cea.papyrus.diagram.sequence.sedi.edit.command.DecideGuardBoundsCommand;
import com.cea.papyrus.diagram.sequence.sedi.edit.command.OperandUtils;
import com.cea.papyrus.diagram.sequence.sedi.model.command.MoveGuardCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.command.SetConstraintCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.command.diagram.SetBoundsHintCommand;
import com.cea.papyrus.diagram.sequence.sedi.model.util.ModelUtil;
import com.cea.papyrus.diagraminterchange2.di2.Diagram;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;

/**
 * Handles layout of Guards on InteractionOperands.
 * 
 * @author frankd@ifi.uio.no
 */
public class GuardLayoutHandler {

    @SuppressWarnings("unchecked")
    public Rectangle layout(final Diagram diagram, final InteractionConstraint constraint,
            final EditPart anyEditPart) {

        InteractionOperand operand = (InteractionOperand) constraint.getOwner();
        Rectangle operandBounds = OperandUtils.getOperandBounds(diagram, operand, anyEditPart);

        CombinedFragment cfragment = (CombinedFragment) operand.getOwner();
        GraphNode cfragmentView = ModelUtil.getGraphNode(cfragment, diagram);
        Rectangle cfragmentBounds =
                new Rectangle(cfragmentView.getPosition(), cfragmentView.getSize());

        return new Rectangle(30, operandBounds.y - cfragmentBounds.y, 1, 1); // slightly
        // inside
        // the
        // operand

        // TODO Try to locate a lifeline to center on
    }

    @SuppressWarnings("unchecked")
    public Command[] getMoveCommands(final EditPart cfEditPart, final EditPart host,
            final Rectangle suggestedBounds) {

        final GraphicalEditPart cfragmentEP = (GraphicalEditPart) cfEditPart;
        final GraphicalEditPart guardEP = (GraphicalEditPart) host;
        final GraphNode guardView = (GraphNode) guardEP.getModel();

        final Point suggestedLocation = suggestedBounds.getLocation();

        Point suggestedLocAbs = suggestedLocation.getCopy();
        cfragmentEP.getFigure().translateToParent(suggestedLocAbs);
        cfragmentEP.getFigure().translateToAbsolute(suggestedLocAbs);

        // Check if the current point is acceptable:
        // 1. the owner is an InteractionOperand, and
        // 2. it does not already have a guard
        final Diagram diagram = LookForElement.getDiagram(guardView);
        final AnalyseOwnerCommand analyseOwnerCmd = new AnalyseOwnerCommand();
        analyseOwnerCmd.setAnyEditPart(guardEP);
        analyseOwnerCmd.setDiagram(diagram);
        analyseOwnerCmd.setLocation(suggestedLocAbs);
        analyseOwnerCmd.execute();
        if (!(analyseOwnerCmd.getOwner() instanceof InteractionOperand))
            return null;
        final InteractionOperand ownerOperand = (InteractionOperand) analyseOwnerCmd.getOwner();
        if (ownerOperand.getGuard() != null
                && ownerOperand.getGuard() != ModelUtil.getSemantic(guardView))
            return null;

        final DecideGuardBoundsCommand analyseBoundsCmd = new DecideGuardBoundsCommand();
        analyseBoundsCmd.setAnyEditPart(guardEP);
        analyseBoundsCmd.setDiagram(diagram);
        analyseBoundsCmd.setHint(new Rectangle(suggestedLocAbs.x, suggestedLocAbs.y, 0, 0));
        analyseBoundsCmd.setOperand(ownerOperand);

        final SetBoundsHintCommand boundsHint = new SetBoundsHintCommand();
        // glue: hint

        final SetConstraintCommand boundsCmd = new SetConstraintCommand();
        boundsCmd.setElement(guardView);
        // glue: bounds

        final MoveGuardCommand moveCmd = new MoveGuardCommand();
        moveCmd.setGuard(ModelUtil.<InteractionConstraint> getSemantic(guardView));
        moveCmd.setOperand(ownerOperand);

        final Command glue1 = new Command() {
            public void execute() {
                // convert to coords local to CF
                Rectangle bounds = analyseBoundsCmd.getPreferredBounds();
                cfragmentEP.getFigure().translateToRelative(bounds);
                cfragmentEP.getFigure().translateFromParent(bounds);
                boundsHint.setHint(bounds);
                boundsCmd.setBounds(bounds);
            }
        };

        // TODO Snap to nearest lifeline, if any, that is covered by the operand

        return new Command[] {
                analyseBoundsCmd, glue1, boundsHint, boundsCmd, moveCmd
        };
    }
}
